/*
 * Copyright (C) 2020 Agrui
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef CLASS_H
#define CLASS_H

#include <OSMemory.h>
#include "obj.h"

#ifdef __cplusplus
extern "C" {
#endif


#define CLASS(ClassType)                 \
    typedef struct ClassType ClassType;      \
    void delete##ClassType(ClassType* self); \
    void __load_class_##ClassType##__(ClassType*); \
    struct ClassType

#define INHERIT(Parent) \
    struct Parent mParent

#define CLASS_META \
    struct __OBJ_base base


#define NEW_INSTANCE(ClassType, ...) \
    int size = sizeof(ClassType) + sizeof(struct __OBJ_base); \
    struct __OBJ_base* obj = (struct __OBJ_base*)OS_MALLOC(size); \
    if (!obj) { \
        return NULL; \
    } \
    memset(obj, 0 ,sizeof(size)); \
    OBJ_SETUP(obj); \
    ClassType* self = (ClassType*)OBJ_TO_SELF(obj); \
    __load_class_##ClassType##__(self);\
    if (self->__init__) { \
        self->__init__(self, __VA_ARGS__); \
    } \
    return self

#define NEW_INSTANCE_0(ClassType) \
    int size = sizeof(ClassType) + sizeof(struct __OBJ_base); \
    struct __OBJ_base* obj = (struct __OBJ_base*)OS_MALLOC(size); \
    if (!obj) { \
        return NULL; \
    } \
    memset(obj, 0 ,sizeof(size)); \
    OBJ_SETUP(obj); \
    ClassType* self = (ClassType*)OBJ_TO_SELF(obj); \
    __load_class_##ClassType##__(self);\
    if (self->__init__) { \
        self->__init__(self); \
    } \
    return self


#define NEW(ClassType) \
    ClassType* new##ClassType() { \
        NEW_INSTANCE_0(ClassType); \
    }


#define NEW_1(ClassType, T1) \
    ClassType* new##ClassType(T1 arg1) { \
        NEW_INSTANCE(ClassType, arg1); \
    }

#define NEW_2(ClassType, T1, T2) \
    ClassType* new##ClassType(T1 arg1, T2 arg2) { \
        NEW_INSTANCE(ClassType, arg1, arg2); \
    }

#define NEW_3(ClassType, T1, T2, T3) \
    ClassType* new##ClassType(T1 arg1, T2 arg2, T3 arg3) { \
        NEW_INSTANCE(ClassType, arg1, arg2, arg3); \
    }

#define NEW_4(ClassType, T1, T2, T3, T4) \
    ClassType* new##ClassType(T1 arg1, T2 arg2, T3 arg3, T4 arg4) { \
        NEW_INSTANCE(ClassType, arg1, arg2, arg3, arg4); \
    }


#define DELETE(ClassType) \
    void delete##ClassType(ClassType* self) { \
        if (self->__deinit__) { \
            self->__deinit__(self); \
        } \
        (SELF_TO_OBJ(self))->release(); \
        OS_FREE(SELF_TO_OBJ(self)); \
    }


#define SUPER(child, parent) ((parent*)(&(child->mParent)))
#define CHILD(obj, parent, child) (child*)(obj-(int)__builtin_offsetof(child, mParent))

#define SET_MEMBER(ClassType, a) \
    self->a = ClassType##_##a

#define SET_VIRTUAL_MEMBER(Child, Parent, a)  \
    do { \
        self->a = Child##_##a; \
        Parent* p = SUPER(self, Parent); \
        p->a = Child##_##a; \
    } while(0)

#define MEMBER_IMPLMENET(ClassType) \
    NEW(ClassType); \
    DELETE(ClassType);


#define MEMBER_IMPLMENET_1(ClassType, T1) \
    NEW_1(ClassType, T1); \
    DELETE(ClassType)

#define MEMBER_IMPLMENET_2(ClassType, T1, T2) \
    NEW_2(ClassType, T1, T2); \
    DELETE(ClassType)

#define MEMBER_IMPLMENET_3(ClassType, T1, T2, T3) \
    NEW_3(ClassType, T1, T2, T3); \
    DELETE(ClassType)

#define MEMBER_IMPLMENET_4(ClassType, T1, T2, T3, T4) \
    NEW_4(ClassType, T1, T2, T3, T4); \
    DELETE(ClassType)

#define LOAD_CLASS(ClassType) \
    MEMBER_IMPLMENET(ClassType); \
    void __load_class_##ClassType##__(ClassType* self)

#define LOAD_CLASS_ARG1(ClassType, T1) \
    MEMBER_IMPLMENET_1(ClassType, T1); \
    void __load_class_##ClassType##__(ClassType* self)

#define LOAD_CLASS_ARG2(ClassType, T1, T2) \
    MEMBER_IMPLMENET_2(ClassType, T1, T2); \
    void __load_class_##ClassType##__(ClassType* self)

#define LOAD_CLASS_ARG3(ClassType, T1, T2, T3) \
    MEMBER_IMPLMENET_3(ClassType, T1, T2, T3); \
    void __load_class_##ClassType##__(ClassType* self)

#define LOAD_CLASS_ARG4(ClassType, T1, T2, T3, T4) \
    MEMBER_IMPLMENET_4(ClassType, T1, T2, T3, T4); \
    void __load_class_##ClassType##__(ClassType* self)

#define PUBLIC_CLASS_METHOD(ClassType, Func) \
    extern __typeof__(((ClassType*)0)->Func) ClassType##_##Func

#define DEF_CLASS_METHOD(ClassType, Func, baseFunc) \
    __typeof__(((ClassType*)0)->Func) ClassType##_##Func = baseFunc

#ifdef __cplusplus
}
#endif

#endif
